package com.matrix.framework.sysconfig.iplist.filter;

import com.matrix.framework.sysconfig.iplist.data.IpAccessRecordPo;
import com.matrix.framework.sysconfig.iplist.service.IpSecurityService;
import com.matrix.framework.core.i18n.I18n;
import com.matrix.framework.core.i18n.MessageConstants;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * IP安全过滤器
 *
 * Copyright © 海平面工作室 版权所有
 *
 * @Author: Leo
 * @Create: 2024/12/1 15:30
 * @Since 1.2
 */
@Component
@Order(1) // 高优先级，在认证之前执行
public class IpSecurityFilter implements WebFilter {

    private final IpSecurityService ipSecurityService;

    public IpSecurityFilter(IpSecurityService ipSecurityService) {
        this.ipSecurityService = ipSecurityService;
    }

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
        String ipAddress = getClientIpAddress(exchange);
        String apiPath = exchange.getRequest().getPath().value();
        String username = extractUsername(exchange);

        // 记录访问开始时间
        long startTime = System.currentTimeMillis();

        return ipSecurityService.validateIpAccess(ipAddress, username, apiPath)
                .flatMap(validationResult -> {
                    if (validationResult.isAllowed()) {
                        // IP验证通过，继续处理请求
                        return chain.filter(exchange)
                                .doFinally(signalType -> recordAccessResult(exchange, ipAddress, username, apiPath, startTime, "SUCCESS", null));
                    } else {
                        // IP验证失败，返回错误响应
                        return handleIpValidationFailure(exchange, validationResult, ipAddress, username, apiPath, startTime);
                    }
                })
                .onErrorResume(e -> {
                    // 发生异常，记录失败
                    recordAccessResult(exchange, ipAddress, username, apiPath, startTime, "FAILED", e.getMessage());
                    return handleError(exchange, e);
                });
    }

    /**
     * 获取客户端IP地址
     */
    private String getClientIpAddress(ServerWebExchange exchange) {
        // 尝试从各种头部获取真实IP
        String xForwardedFor = exchange.getRequest().getHeaders().getFirst("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty()) {
            return xForwardedFor.split(",")[0].trim();
        }

        String xRealIp = exchange.getRequest().getHeaders().getFirst("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty()) {
            return xRealIp.trim();
        }

        String xClientIp = exchange.getRequest().getHeaders().getFirst("X-Client-IP");
        if (xClientIp != null && !xClientIp.isEmpty()) {
            return xClientIp.trim();
        }

        // 从连接中获取IP
        InetSocketAddress remoteAddress = exchange.getRequest().getRemoteAddress();
        if (remoteAddress != null) {
            return remoteAddress.getAddress().getHostAddress();
        }

        return "127.0.0.1"; // 默认IP
    }

    /**
     * 提取用户名（如果已认证）
     */
    private String extractUsername(ServerWebExchange exchange) {
        // 从JWT token中提取用户名
        String authHeader = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (authHeader != null && authHeader.startsWith("Bearer ")) {
            // 这里可以解析JWT token获取用户名
            // 为了简化，暂时返回null
            return null;
        }
        return null;
    }

    /**
     * 处理IP验证失败
     */
    private Mono<Void> handleIpValidationFailure(ServerWebExchange exchange, 
                                                IpSecurityService.IpValidationResult validationResult,
                                                String ipAddress, String username, String apiPath, 
                                                long startTime) {
        // 记录阻止的访问
        recordAccessResult(exchange, ipAddress, username, apiPath, startTime, "BLOCKED", validationResult.getReason());

        // 设置响应状态
        exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

        // 构建错误响应
        String errorResponse = String.format(
                "{\"code\":403,\"message\":\"%s\",\"success\":false,\"data\":{\"ip\":\"%s\",\"reason\":\"%s\"}}",
                I18n.getMessage(MessageConstants.RESPONSE_PERMISSION),
                ipAddress,
                validationResult.getReason()
        );

        return exchange.getResponse()
                .writeWith(Mono.just(exchange.getResponse()
                        .bufferFactory()
                        .wrap(errorResponse.getBytes(StandardCharsets.UTF_8))));
    }

    /**
     * 处理异常
     */
    private Mono<Void> handleError(ServerWebExchange exchange, Throwable error) {
        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);

        String errorResponse = String.format(
                "{\"code\":500,\"message\":\"%s\",\"success\":false}",
                I18n.getMessage(MessageConstants.RESPONSE_SERVICE_ERROR)
        );

        return exchange.getResponse()
                .writeWith(Mono.just(exchange.getResponse()
                        .bufferFactory()
                        .wrap(errorResponse.getBytes(StandardCharsets.UTF_8))));
    }

    /**
     * 记录访问结果
     */
    private void recordAccessResult(ServerWebExchange exchange, String ipAddress, String username, 
                                  String apiPath, long startTime, String result, String reason) {
        IpAccessRecordPo record = new IpAccessRecordPo();
        record.setIpAddress(ipAddress);
        record.setUsername(username);
        record.setApiPath(apiPath);
        record.setUserAgent(exchange.getRequest().getHeaders().getFirst("User-Agent"));
        record.setRequestMethod(exchange.getRequest().getMethod().name());
        record.setResponseStatus(exchange.getResponse().getStatusCode().value());
        record.setResponseTime(System.currentTimeMillis() - startTime);
        record.setResult(result);
        record.setReason(reason);
        record.setAccessTime(System.currentTimeMillis());
        record.setCreateTime(System.currentTimeMillis());

        // 异步记录访问结果
        ipSecurityService.recordIpAccess(record)
                .subscribe(
                        (Void v) -> {
                            // 记录成功
                        },
                        (Throwable error) -> {
                            // 记录失败，但不影响主流程
                            System.err.println("Failed to record IP access: " + error.getMessage());
                        }
                );
    }
} 